# Tooltip

<Subtitle>
  A popup that appears when an element is hovered or focused, showing a hint for sighted users.
</Subtitle>
<Meta
  name="description"
  content="A high-quality, unstyled React tooltip component that appears when an element is hovered or focused, showing a hint for sighted users."
/>

import { DemoTooltipHero } from './demos/hero';

<DemoTooltipHero />

## Usage guidelines

To ensure that tooltips are accessible and helpful, follow these guidelines:

- **Provide an accessible name for the trigger**: The tooltip's trigger must have a meaningful label. This can be its visible text or an `aria-label`/`aria-labelledby` attribute. The label should closely match the tooltip's content to ensure consistency for screen reader users.
- **Avoid tooltips for critical information**: Tooltips work well for enhancing UI clarity (like labeling icon buttons) but should not be the sole means of conveying important information. Since tooltips do not appear on touch devices, consider using a [Popover](/react/components/popover) for essential content.
- **Avoid tooltips for "infotips"**: If your tooltip is attached to an "info icon" button whose only purpose is to show the tooltip, opt for [Popover](/react/components/popover) and add the `openOnHover` prop instead. Tooltips should describe an element that performs an action separate from opening the tooltip itself.
- **Avoid for transient information**: Use the Toast component's [anchoring ability](/react/components/toast#anchored-toasts) instead of Tooltip for transient notifications, like a "Copied" popup that appears above a copy-to-clipboard button. This way, the message is announced to screen readers when it appears. Toasts can also contain more complex content, such as links or actions.

## Anatomy

Import the component and assemble its parts:

```jsx title="Anatomy"
import { Tooltip } from '@base-ui-components/react/tooltip';

<Tooltip.Provider>
  <Tooltip.Root>
    <Tooltip.Trigger />
    <Tooltip.Portal>
      <Tooltip.Positioner>
        <Tooltip.Popup>
          <Tooltip.Arrow />
        </Tooltip.Popup>
      </Tooltip.Positioner>
    </Tooltip.Portal>
  </Tooltip.Root>
</Tooltip.Provider>;
```

## API reference

<Reference component="Tooltip" parts="Provider, Root, Trigger, Portal, Positioner, Popup, Arrow" />

## Examples

### Detached triggers

A tooltip can be controlled by a trigger located either inside or outside the `<Tooltip.Root>` component.
For simple, one-off interactions, place the `<Tooltip.Trigger>` inside `<Tooltip.Root>`, as shown in the example at the top of this page.

However, if defining the tooltip's content next to its trigger is not practical, you can use a detached trigger.
This involves placing the `<Tooltip.Trigger>` outside of `<Tooltip.Root>` and linking them with a `handle` created by the `Tooltip.createHandle()` function.

```jsx title="Detached triggers" {3,5} "handle={demoTooltip}"
const demoTooltip = Tooltip.createHandle();

<Tooltip.Trigger handle={demoTooltip}>Button</Tooltip.Trigger>

<Tooltip.Root handle={demoTooltip}>
  ...
</Tooltip.Root>
```

import { DemoTooltipDetachedTriggersSimple } from './demos/detached-triggers-simple';

<DemoTooltipDetachedTriggersSimple />

### Multiple triggers

A single tooltip can be opened by multiple trigger elements.
You can achieve this by using the same `handle` for several detached triggers, or by placing multiple `<Tooltip.Trigger>` components inside a single `<Tooltip.Root>`.

```jsx title="Multiple triggers within the Root part"
<Tooltip.Root>
  <Tooltip.Trigger>Trigger 1</Tooltip.Trigger>
  <Tooltip.Trigger>Trigger 2</Tooltip.Trigger>
  ...
</Tooltip.Root>
```

```jsx title="Multiple detached triggers"
const demoTooltip = Tooltip.createHandle();

<Tooltip.Trigger handle={demoTooltip}>
  Trigger 1
</Tooltip.Trigger>

<Tooltip.Trigger handle={demoTooltip}>
  Trigger 2
</Tooltip.Trigger>

<Tooltip.Root handle={demoTooltip}>
  ...
</Tooltip.Root>
```

The tooltip can render different content depending on which trigger opened it.
This is achieved by passing a `payload` to the `<Tooltip.Trigger>` and using the function-as-a-child pattern in `<Tooltip.Root>`.

The payload can be strongly typed by providing a type argument to the `createHandle()` function:

```jsx title="Detached triggers with payload" {1,3,7} "payload"
const demoTooltip = Tooltip.createHandle<{ text: string }>();

<Tooltip.Trigger handle={demoTooltip} payload={{ text: 'Trigger 1' }}>
  Trigger 1
</Tooltip.Trigger>

<Tooltip.Trigger handle={demoTooltip} payload={{ text: 'Trigger 2' }}>
  Trigger 2
</Tooltip.Trigger>

<Tooltip.Root handle={demoTooltip}>
  {({ payload }) => (
    <Tooltip.Portal>
      <Tooltip.Positioner sideOffset={8}>
        <Tooltip.Popup className={styles.Popup}>
          <Tooltip.Arrow className={styles.Arrow}>
            <ArrowSvg />
          </Tooltip.Arrow>
          {payload !== undefined && (
            <span>
              Tooltip opened by {payload.text}
            </span>
          )}
        </Tooltip.Popup>
      </Tooltip.Positioner>
    </Tooltip.Portal>
  )}
</Tooltip.Root>
```

### Controlled mode with multiple triggers

You can control the tooltip's open state externally using the `open` and `onOpenChange` props on `<Tooltip.Root>`.
This allows you to manage the tooltip's visibility based on your application's state.
When using multiple triggers, you have to manage which trigger is active with the `triggerId` prop on `<Tooltip.Root>` and the `id` prop on each `<Tooltip.Trigger>`.

Note that there is no separate `onTriggerIdChange` prop.
Instead, the `onOpenChange` callback receives an additional argument, `eventDetails`, which contains the trigger element that initiated the state change.

import { DemoTooltipDetachedTriggersControlled } from './demos/detached-triggers-controlled';

<DemoTooltipDetachedTriggersControlled />

### Animating the Tooltip

You can animate a tooltip as it moves between different trigger elements.
This includes animating its position, size, and content.

#### Position and Size

To animate the tooltip's position, apply CSS transitions to the `left`, `right`, `top`, and `bottom` properties of the **Positioner** part.
To animate its size, transition the `width` and `height` of the **Popup** part.

#### Content

The tooltip also supports content transitions.
This is useful when different triggers display different content within the same tooltip.

To enable content animations, wrap the content in the `<Tooltip.Viewport>` part.
This part provides features to create direction-aware animations.
It renders a `div` with a `data-activation-direction` attribute (`left`, `right`, `up`, or `down`) that indicates the new trigger's position relative to the previous one.

Inside the `<Tooltip.Viewport>`, the content is further wrapped in `div`s with data attributes to help with styling:

- `data-current`: The currently visible content when no transitions are present or the incoming content.
- `data-previous`: The outgoing content during a transition.

You can use these attributes to style the enter and exit animations.

import { DemoTooltipDetachedTriggersFull } from './demos/detached-triggers-full';

<DemoTooltipDetachedTriggersFull />
